home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / stdlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-01  |  11.0 KB  |  499 lines

  1. /* 
  2.  * stdlib.c --
  3.  *
  4.  *    Source code for the "strto?" library procedures.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/lib/c/stdlib/RCS/strtod.c,v 1.2 89/03/22 00:47:27 rab Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <ctype.h>
  21.  
  22. #ifndef TRUE
  23. #define TRUE 1
  24. #define FALSE 0
  25. #endif
  26. #ifndef NULL
  27. #define NULL 0
  28. #endif
  29.  
  30. double strtod();
  31. long strtol();
  32. unsigned long int strtoul();
  33.  
  34. static int maxExponent = 511;    /* Largest possible base 10 exponent.  Any
  35.                  * exponent larger than this will already
  36.                  * produce underflow or overflow, so there's
  37.                  * no need to worry about additional digits.
  38.                  */
  39. static double powersOf10[] = {    /* Table giving binary powers of 10.  Entry */
  40.     10.,            /* is 10^2^i.  Used to convert decimal */
  41.     100.,            /* exponents into floating-point numbers. */
  42.     1.0e4,
  43.     1.0e8,
  44.     1.0e16,
  45.     1.0e32,
  46.     1.0e64,
  47.     1.0e128,
  48.     1.0e256
  49. };
  50.  
  51. /*
  52.  *----------------------------------------------------------------------
  53.  *
  54.  * strtod --
  55.  *
  56.  *    This procedure converts a floating-point number from an ASCII
  57.  *    decimal representation to internal double-precision format.
  58.  *
  59.  * Results:
  60.  *    The return value is the double-precision floating-point
  61.  *    representation of the characters in string.  If endPtr isn't
  62.  *    NULL, then *endPtr is filled in with the address of the
  63.  *    next character after the last one that was part of the
  64.  *    floating-point number.
  65.  *
  66.  * Side effects:
  67.  *    None.
  68.  *
  69.  *----------------------------------------------------------------------
  70.  */
  71.  
  72. double
  73. strtod(string, endPtr)
  74.     char *string;        /* A decimal ASCII floating-point number,
  75.                  * optionally preceded by white space.
  76.                  * Must have form "-I.FE-X", where I is the
  77.                  * integer part of the mantissa, F is the
  78.                  * fractional part of the mantissa, and X
  79.                  * is the exponent.  Either of the signs
  80.                  * may be "+", "-", or omitted.  Either I
  81.                  * or F may be omitted, or both.  The decimal
  82.                  * point isn't necessary unless F is present.
  83.                  * The "E" may actually be an "e".  E and X
  84.                  * may both be omitted (but not just one).
  85.                  */
  86.     char **endPtr;        /* If non-NULL, store terminating character's
  87.                  * address here. */
  88. {
  89.     int sign, expSign = FALSE;
  90.     double fraction, dblExp, *d;
  91.     register char *p, c;
  92.     int exp = 0;        /* Exponent read from "EX" field. */
  93.     int fracExp = 0;        /* Exponent that derives from the fractional
  94.                  * part.  Under normal circumstatnces, it is
  95.                  * the negative of the number of digits in F.
  96.                  * However, if I is very long, the last digits
  97.                  * of I get dropped (otherwise a long I with a
  98.                  * large negative exponent could cause an
  99.                  * unnecessary overflow on I alone).  In this
  100.                  * case, fracExp is incremented one for each
  101.                  * dropped digit.
  102.                  */
  103.     int mantSize;        /* Number of digits in mantissa. */
  104.     int decPt;            /* Number of mantissa digits BEFORE decimal
  105.                  * point.
  106.                  */
  107.     char *pExp;            /* Temporarily holds location of exponent
  108.                  * in string.
  109.                  */
  110.  
  111.     /*
  112.      * Strip off leading blanks and check for a sign.
  113.      */
  114.  
  115.     p = string;
  116.     while (isspace(*p)) {
  117.     p += 1;
  118.     }
  119.     if (*p == '-') {
  120.     sign = TRUE;
  121.     p += 1;
  122.     } else {
  123.     if (*p == '+') {
  124.         p += 1;
  125.     }
  126.     sign = FALSE;
  127.     }
  128.  
  129.     /*
  130.      * Count the number of digits in the mantissa (including the decimal
  131.      * point), and also locate the decimal point.
  132.      */
  133.  
  134.     decPt = -1;
  135.     for (mantSize = 0; ; mantSize += 1)
  136.     {
  137.     c = *p;
  138.     if (!isdigit(c)) {
  139.         if ((c != '.') || (decPt >= 0)) {
  140.         break;
  141.         }
  142.         decPt = mantSize;
  143.     }
  144.     p += 1;
  145.     }
  146.  
  147.     /*
  148.      * Now suck up the digits in the mantissa.  Use two integers to
  149.      * collect 9 digits each (this is faster than using floating-point).
  150.      * If the mantissa has more than 18 digits, ignore the extras, since
  151.      * they can't affect the value anyway.
  152.      */
  153.     
  154.     pExp  = p;
  155.     p -= mantSize;
  156.     if (decPt < 0) {
  157.     decPt = mantSize;
  158.     } else {
  159.     mantSize -= 1;            /* One of the digits was the point. */
  160.     }
  161.     if (mantSize > 18) {
  162.     fracExp = decPt - 18;
  163.     mantSize = 18;
  164.     } else {
  165.     fracExp = decPt - mantSize;
  166.     }
  167.     if (mantSize == 0) {
  168.     fraction = 0.0;
  169.     p = string;
  170.     goto done;
  171.     } else {
  172.     int frac1, frac2;
  173.     frac1 = 0;
  174.     for ( ; mantSize > 9; mantSize -= 1)
  175.     {
  176.         c = *p;
  177.         p += 1;
  178.         if (c == '.') {
  179.         c = *p;
  180.         p += 1;
  181.         }
  182.         frac1 = 10*frac1 + (c - '0');
  183.     }
  184.     frac2 = 0;
  185.     for (; mantSize > 0; mantSize -= 1)
  186.     {
  187.         c = *p;
  188.         p += 1;
  189.         if (c == '.') {
  190.         c = *p;
  191.         p += 1;
  192.         }
  193.         frac2 = 10*frac2 + (c - '0');
  194.     }
  195.     fraction = (1.0e9 * frac1) + frac2;
  196.     }
  197.  
  198.     /*
  199.      * Skim off the exponent.
  200.      */
  201.  
  202.     p = pExp;
  203.     if ((*p == 'E') || (*p == 'e')) {
  204.     p += 1;
  205.     if (*p == '-') {
  206.         expSign = TRUE;
  207.         p += 1;
  208.     } else {
  209.         if (*p == '+') {
  210.         p += 1;
  211.         }
  212.         expSign = FALSE;
  213.     }
  214.     while (isdigit(*p)) {
  215.         exp = exp * 10 + (*p - '0');
  216.         p += 1;
  217.     }
  218.     }
  219.     if (expSign) {
  220.     exp = fracExp - exp;
  221.     } else {
  222.     exp = fracExp + exp;
  223.     }
  224.  
  225.     /*
  226.      * Generate a floating-point number that represents the exponent.
  227.      * Do this by processing the exponent one bit at a time to combine
  228.      * many powers of 2 of 10. Then combine the exponent with the
  229.      * fraction.
  230.      */
  231.     
  232.     if (exp < 0) {
  233.     expSign = TRUE;
  234.     exp = -exp;
  235.     } else {
  236.     expSign = FALSE;
  237.     }
  238.     if (exp > maxExponent) {
  239.     exp = maxExponent;
  240.     }
  241.     dblExp = 1.0;
  242.     for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
  243.     if (exp & 01) {
  244.         dblExp *= *d;
  245.     }
  246.     }
  247.     if (expSign) {
  248.     fraction /= dblExp;
  249.     } else {
  250.     fraction *= dblExp;
  251.     }
  252.  
  253. done:
  254.     if (endPtr != NULL) {
  255.     *endPtr = p;
  256.     }
  257.  
  258.     if (sign) {
  259.     return -fraction;
  260.     }
  261.     return fraction;
  262. }
  263.  
  264.  
  265. /*
  266.  *----------------------------------------------------------------------
  267.  *
  268.  * strtol --
  269.  *
  270.  *    Convert an ASCII string into an integer.
  271.  *
  272.  * Results:
  273.  *    The return value is the integer equivalent of string.  If endPtr
  274.  *    is non-NULL, then *endPtr is filled in with the character
  275.  *    after the last one that was part of the integer.  If string
  276.  *    doesn't contain a valid integer value, then zero is returned
  277.  *    and *endPtr is set to string.
  278.  *
  279.  * Side effects:
  280.  *    None.
  281.  *
  282.  *----------------------------------------------------------------------
  283.  */
  284.  
  285. long int
  286. strtol(string, endPtr, base)
  287.     char *string;        /* String of ASCII digits, possibly
  288.                  * preceded by white space.  For bases
  289.                  * greater than 10, either lower- or
  290.                  * upper-case digits may be used.
  291.                  */
  292.     char **endPtr;        /* Where to store address of terminating
  293.                  * character, or NULL. */
  294.     int base;            /* Base for conversion.  Must be less
  295.                  * than 37.  If 0, then the base is chosen
  296.                  * from the leading characters of string:
  297.                  * "0x" means hex, "0" means octal, anything
  298.                  * else means decimal.
  299.                  */
  300. {
  301.     register char *p;
  302.     int result;
  303.  
  304.     /*
  305.      * Skip any leading blanks.
  306.      */
  307.  
  308.     p = string;
  309.     while (isspace(*p)) {
  310.     p += 1;
  311.     }
  312.  
  313.     /*
  314.      * Check for a sign.
  315.      */
  316.  
  317.     if (*p == '-') {
  318.     p += 1;
  319.     result = -(strtoul(p, endPtr, base));
  320.     } else {
  321.     if (*p == '+') {
  322.         p += 1;
  323.     }
  324.     result = strtoul(p, endPtr, base);
  325.     }
  326.     if ((result == 0) && (endPtr != 0) && (*endPtr == p)) {
  327.     *endPtr = string;
  328.     }
  329.     return result;
  330. }
  331.  
  332. /*
  333.  * The table below is used to convert from ASCII digits to a
  334.  * numerical equivalent.  It maps from '0' through 'z' to integers
  335.  * (100 for non-digit characters).
  336.  */
  337.  
  338. static char cvtIn[] = {
  339.     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,        /* '0' - '9' */
  340.     100, 100, 100, 100, 100, 100, 100,        /* punctuation */
  341.     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,    /* 'A' - 'Z' */
  342.     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  343.     30, 31, 32, 33, 34, 35,
  344.     100, 100, 100, 100, 100, 100,        /* punctuation */
  345.     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,    /* 'a' - 'z' */
  346.     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  347.     30, 31, 32, 33, 34, 35};
  348.  
  349. /*
  350.  *----------------------------------------------------------------------
  351.  *
  352.  * strtoul --
  353.  *
  354.  *    Convert an ASCII string into an integer.
  355.  *
  356.  * Results:
  357.  *    The return value is the integer equivalent of string.  If endPtr
  358.  *    is non-NULL, then *endPtr is filled in with the character
  359.  *    after the last one that was part of the integer.  If string
  360.  *    doesn't contain a valid integer value, then zero is returned
  361.  *    and *endPtr is set to string.
  362.  *
  363.  * Side effects:
  364.  *    None.
  365.  *
  366.  *----------------------------------------------------------------------
  367.  */
  368.  
  369. unsigned long int
  370. strtoul(string, endPtr, base)
  371.     char *string;        /* String of ASCII digits, possibly
  372.                  * preceded by white space.  For bases
  373.                  * greater than 10, either lower- or
  374.                  * upper-case digits may be used.
  375.                  */
  376.     char **endPtr;        /* Where to store address of terminating
  377.                  * character, or NULL. */
  378.     int base;            /* Base for conversion.  Must be less
  379.                  * than 37.  If 0, then the base is chosen
  380.                  * from the leading characters of string:
  381.                  * "0x" means hex, "0" means octal, anything
  382.                  * else means decimal.
  383.                  */
  384. {
  385.     register char *p;
  386.     register unsigned long int result = 0;
  387.     register unsigned digit;
  388.     int anyDigits = FALSE;
  389.  
  390.     /*
  391.      * Skip any leading blanks.
  392.      */
  393.  
  394.     p = string;
  395.     while (isspace(*p)) {
  396.     p += 1;
  397.     }
  398.  
  399.     /*
  400.      * If no base was provided, pick one from the leading characters
  401.      * of the string.
  402.      */
  403.     
  404.     if (base == 0)
  405.     {
  406.     if (*p == '0') {
  407.         p += 1;
  408.         if (*p == 'x') {
  409.         p += 1;
  410.         base = 16;
  411.         } else {
  412.  
  413.         /*
  414.          * Must set anyDigits here, otherwise "0" produces a
  415.          * "no digits" error.
  416.          */
  417.  
  418.         anyDigits = TRUE;
  419.         base = 8;
  420.         }
  421.     }
  422.     else base = 10;
  423.     } else if (base == 16) {
  424.  
  425.     /*
  426.      * Skip a leading "0x" from hex numbers.
  427.      */
  428.  
  429.     if ((p[0] == '0') && (p[1] == 'x')) {
  430.         p += 2;
  431.     }
  432.     }
  433.  
  434.     /*
  435.      * Sorry this code is so messy, but speed seems important.  Do
  436.      * different things for base 8, 10, 16, and other.
  437.      */
  438.  
  439.     if (base == 8) {
  440.     for ( ; ; p += 1) {
  441.         digit = *p - '0';
  442.         if (digit > 7) {
  443.         break;
  444.         }
  445.         result = (result << 3) + digit;
  446.         anyDigits = TRUE;
  447.     }
  448.     } else if (base == 10) {
  449.     for ( ; ; p += 1) {
  450.         digit = *p - '0';
  451.         if (digit > 9) {
  452.         break;
  453.         }
  454.         result = (10*result) + digit;
  455.         anyDigits = TRUE;
  456.     }
  457.     } else if (base == 16) {
  458.     for ( ; ; p += 1) {
  459.         digit = *p - '0';
  460.         if (digit > ('z' - '0')) {
  461.         break;
  462.         }
  463.         digit = cvtIn[digit];
  464.         if (digit > 15) {
  465.         break;
  466.         }
  467.         result = (result << 4) + digit;
  468.         anyDigits = TRUE;
  469.     }
  470.     } else {
  471.     for ( ; ; p += 1) {
  472.         digit = *p - '0';
  473.         if (digit > ('z' - '0')) {
  474.         break;
  475.         }
  476.         digit = cvtIn[digit];
  477.         if (digit >= base) {
  478.         break;
  479.         }
  480.         result = result*base + digit;
  481.         anyDigits = TRUE;
  482.     }
  483.     }
  484.  
  485.     /*
  486.      * See if there were any digits at all.
  487.      */
  488.  
  489.     if (!anyDigits) {
  490.     p = string;
  491.     }
  492.  
  493.     if (endPtr != NULL) {
  494.     *endPtr = p;
  495.     }
  496.  
  497.     return result;
  498. }
  499.